/*
 * @ : Copyright (c) 2020 Phytium Information Technology, Inc. 
 *  
 * SPDX-License-Identifier: Apache-2.0.
 * 
 * @Date: 2021-05-27 14:12:51
 * @LastEditTime: 2021-09-04 22:56:46
 * @Description:  This files is for 
 * 
 * @Modify History: 
 *  Ver   Who        Date         Changes
 * ----- ------     --------    --------------------------------------
 */

#include "gicv3.h"
#include "gicv3_cpuif.h"
#include "ft_types.h"
#include "ft_assert.h"
#include "_cpu.h"
#include <stdio.h>

#ifndef FT_CPUS_NR
#define FT_CPUS_NR 4

#endif

#define GIC_MAX_NR FT_CPUS_NR
#define GIC_NR_IRQS 1500

struct ArmGicv3
{
    s32 offset;                     /* the first interrupt index in the vector table */
    u32 redist_hw_base[FT_CPUS_NR]; /* the pointer of the gic redistributor */
    u32 dist_hw_base;               /* the base address of the gic distributor */
    u32 cpu_hw_base[FT_CPUS_NR];    /* the base addrees of the gic cpu interface */
};

/* 'GIC_MAX_NR' is the number of cores */
static struct ArmGicv3 _gic_table[GIC_MAX_NR];
static u32 _gic_max_irq;

/**
 * @name: ArmGicCpuMaskToAffval
 * @msg:
 * @in param cpu_mask:
 * @out param cluster_id: aff1 [0:7],aff2 [8:15],aff3 [16:23]
 * @out param target_list:  Target List. The set of PEs for which SGI interrupts will be generated. Each bit corresponds to the
 *                          PE within a cluster with an Affinity 0 value equal to the bit number.
 * @return {u32} 0 is finish , 1 is data valid
 */
_WEAK u32 ArmGicCpuMaskToAffval(u32 *cpu_mask, u32 *cluster_id, u32 *target_list)
{
    (void)cpu_mask;
    (void)cluster_id;
    (void)target_list;
    return 0;
}

_WEAK u64 GetMainCpuAffval(void)
{
    return 0;
}

int ArmGicGetActiveIrq(u32 index)
{
    int irq;

    FT_ASSERTZERONUM(index < GIC_MAX_NR);

    // __GET_GICV3_REG(ICC_IAR1, irq);
    irq = readIARGrp1();

    irq = (irq & 0x1FFFFFF) + _gic_table[index].offset;
    return irq;
}

void ArmGicAck(u32 index, int irq)
{
    FT_ASSERTVOID(index < GIC_MAX_NR);
    FT_ASSERTVOID(irq >= 0);

    __asm__ volatile("dsb 0xF" ::
                         : "memory");
    writeEOIGrp1(irq);
    // __SET_GICV3_REG(ICC_EOIR1, irq);
}

void ArmGicMask(u32 index, int irq)
{
    u32 mask = 1U << (irq % 32U);

    FT_ASSERTVOID(index < GIC_MAX_NR);

    irq = (irq - _gic_table[index].offset);
    FT_ASSERTVOID(irq >= 0);

    if (irq < 32)
    {
        u32 cpu_id = GetCpuId();
        FT_ASSERTVOID((cpu_id) < FT_CPUS_NR);
        GIC_RDISTSGI_ICENABLER0(_gic_table[index].redist_hw_base[cpu_id]) = mask;
    }
    else
    {
        GIC_DIST_ENABLE_CLEAR(_gic_table[index].dist_hw_base, irq) = mask;
    }
}

void ArmGicUmask(u32 index, int irq)
{
    u32 mask = 1U << (irq % 32U);

    FT_ASSERTVOID(index < GIC_MAX_NR);

    irq = (irq - _gic_table[index].offset);
    FT_ASSERTVOID(irq >= 0);

    if (irq < 32)
    {
        u32 cpu_id = GetCpuId();
        FT_ASSERTVOID((cpu_id) < FT_CPUS_NR);
        GIC_RDISTSGI_ISENABLER0(_gic_table[index].redist_hw_base[cpu_id]) = mask;
    }
    else
    {
        GIC_DIST_ENABLE_SET(_gic_table[index].dist_hw_base, irq) = mask;
    }
}

u32 ArmGicGetPendingIrq(u32 index, int irq)
{
    u32 pend;

    FT_ASSERTZERONUM(index < GIC_MAX_NR);

    irq = (irq - _gic_table[index].offset);
    FT_ASSERTZERONUM(irq >= 0);

    if (irq >= 16)
    {
        pend = (GIC_DIST_PENDING_SET(_gic_table[index].dist_hw_base, irq) >> (irq % 32U)) & 0x1UL;
    }
    else
    {
        /* INTID 0-15 Software Generated Interrupt */
        pend = (GIC_DIST_SPENDSGI(_gic_table[index].dist_hw_base, irq) >> ((irq % 4U) * 8U)) & 0xFFUL;
        /* No CPU identification offered */
        if (pend != 0U)
        {
            pend = 1U;
        }
        else
        {
            pend = 0U;
        }
    }

    return (pend);
}

void ArmGicSetPendingIrq(u32 index, int irq)
{
    FT_ASSERTVOID(index < GIC_MAX_NR);

    irq = (irq - _gic_table[index].offset);
    FT_ASSERTVOID(irq >= 0);

    if (irq >= 16)
    {
        GIC_DIST_PENDING_SET(_gic_table[index].dist_hw_base, irq) = 1U << (irq % 32U);
    }
    else
    {
        /* INTID 0-15 Software Generated Interrupt */
        /* Forward the interrupt to the CPU interface that requested it */
        GIC_DIST_SOFTINT(_gic_table[index].dist_hw_base) = (irq | 0x02000000U);
    }
}

void ArmGicClearPendingIrq(u32 index, int irq)
{
    u32 mask;

    FT_ASSERTVOID(index < GIC_MAX_NR);

    irq = (irq - _gic_table[index].offset);
    FT_ASSERTVOID(irq >= 0);

    if (irq >= 16)
    {
        mask = 1U << (irq % 32U);
        GIC_DIST_PENDING_CLEAR(_gic_table[index].dist_hw_base, irq) = mask;
    }
    else
    {
        mask = 1U << ((irq % 4U) * 8U);
        GIC_DIST_CPENDSGI(_gic_table[index].dist_hw_base, irq) = mask;
    }
}

void ArmGicSetConfiguration(u32 index, int irq, u32 config)
{
    u32 icfgr;
    u32 shift;

    FT_ASSERTVOID(index < GIC_MAX_NR);

    irq = (irq - _gic_table[index].offset);
    FT_ASSERTVOID(irq >= 0);

    icfgr = GIC_DIST_CONFIG(_gic_table[index].dist_hw_base, irq);
    shift = (irq % 16U) << 1U;

    icfgr &= (~(3U << shift));
    icfgr |= (config << shift);

    GIC_DIST_CONFIG(_gic_table[index].dist_hw_base, irq) = icfgr;
}

u32 ArmGicGetConfiguration(u32 index, int irq)
{
    FT_ASSERTZERONUM(index < GIC_MAX_NR);

    irq = (irq - _gic_table[index].offset);
    FT_ASSERTZERONUM(irq >= 0);

    return (GIC_DIST_CONFIG(_gic_table[index].dist_hw_base, irq) >> ((irq % 16U) >> 1U));
}

void ArmGicClearActive(u32 index, int irq)
{
    u32 mask = 1U << (irq % 32U);

    FT_ASSERTVOID(index < GIC_MAX_NR);

    irq = (irq - _gic_table[index].offset);
    FT_ASSERTVOID(irq >= 0);

    GIC_DIST_ACTIVE_CLEAR(_gic_table[index].dist_hw_base, irq) = mask;
}

/* Set up the cpu mask for the specific interrupt */
void ArmGicSetCpu(u32 index, int irq, u32 cpumask)
{
    u32 old_tgt;

    FT_ASSERTVOID(index < GIC_MAX_NR);

    irq = (irq - _gic_table[index].offset);
    FT_ASSERTVOID(irq >= 0);

    old_tgt = GIC_DIST_TARGET(_gic_table[index].dist_hw_base, irq);

    old_tgt &= ~(0x0FFUL << ((irq % 4U) * 8U));
    old_tgt |= cpumask << ((irq % 4U) * 8U);

    GIC_DIST_TARGET(_gic_table[index].dist_hw_base, irq) = old_tgt;
}

u32 ArmGicGetTargetCpu(u32 index, int irq)
{
    FT_ASSERTZERONUM(index < GIC_MAX_NR);

    irq = (irq - _gic_table[index].offset);
    FT_ASSERTZERONUM(irq >= 0);

    return (GIC_DIST_TARGET(_gic_table[index].dist_hw_base, irq) >> ((irq % 4U) * 8U)) & 0xFFUL;
}

void ArmGicSetPriority(u32 index, int irq, u32 priority)
{
    u32 mask;

    FT_ASSERTVOID(index < GIC_MAX_NR);

    irq = (irq - _gic_table[index].offset);
    FT_ASSERTVOID(irq >= 0);

    if (irq < 32)
    {
        u32 cpu_id = GetCpuId();
        FT_ASSERTVOID((cpu_id) < FT_CPUS_NR);

        mask = GIC_RDISTSGI_IPRIORITYR(_gic_table[index].redist_hw_base[cpu_id], irq);
        mask &= ~(0xFFUL << ((irq % 4U) * 8U));
        mask |= ((priority & 0xFFUL) << ((irq % 4U) * 8U));
        GIC_RDISTSGI_IPRIORITYR(_gic_table[index].redist_hw_base[cpu_id], irq) = mask;
    }
    else
    {
        mask = GIC_DIST_PRI(_gic_table[index].dist_hw_base, irq);
        mask &= ~(0xFFUL << ((irq % 4U) * 8U));
        mask |= ((priority & 0xFFUL) << ((irq % 4U) * 8U));
        GIC_DIST_PRI(_gic_table[index].dist_hw_base, irq) = mask;
    }
}

u32 ArmGicGetPriority(u32 index, int irq)
{
    FT_ASSERTZERONUM(index < GIC_MAX_NR);

    irq = (irq - _gic_table[index].offset);
    FT_ASSERTZERONUM(irq >= 0);

    if (irq < 32)
    {
        u32 cpu_id = GetCpuId();

        FT_ASSERTZERONUM((cpu_id) < FT_CPUS_NR);
        return (GIC_RDISTSGI_IPRIORITYR(_gic_table[index].redist_hw_base[cpu_id], irq) >> ((irq % 4U) * 8U)) & 0xFFUL;
    }
    else
    {
        return (GIC_DIST_PRI(_gic_table[index].dist_hw_base, irq) >> ((irq % 4U) * 8U)) & 0xFFUL;
    }
}

void ArmGicSetSystemRegisterEnableMask(u32 index, u32 value)
{
    FT_ASSERTVOID(index < GIC_MAX_NR);

    value &= 0xFFUL;
    /* set priority mask */
    setICC_SRE_EL1(value);
    // __SET_GICV3_REG(ICC_SRE, value);
    __asm__ volatile("isb 0xF" ::
                         : "memory");
}

u32 ArmGicGetSystemRegisterEnableMask(u32 index)
{
    FT_ASSERTZERONUM(index < GIC_MAX_NR);
    u32 value;

    // __GET_GICV3_REG(ICC_SRE, value);
    value = getICC_SRE_EL1();
    return value;
}

void ArmGicSetInterfacePriorMask(u32 index, u32 priority)
{
    FT_ASSERTVOID(index < GIC_MAX_NR);

    priority &= 0xFFUL;
    /* set priority mask */
    setPriorityMask(priority);
    // __SET_GICV3_REG(ICC_PMR, priority);
}

u32 ArmGicGetInterfacePriorMask(u32 index)
{
    FT_ASSERTZERONUM(index < GIC_MAX_NR);
    u32 priority;
    priority = getPriorityMask();
    // __GET_GICV3_REG(ICC_PMR, priority);
    return priority;
}

void ArmGicSetBinaryPoint(u32 index, u32 binary_point)
{
    index = index;
    binary_point &= 0x7U;
    setBPR1(binary_point);
    // __SET_GICV3_REG(ICC_BPR1, binary_point);
}

u32 ArmGicGetBinaryPoint(u32 index)
{
    u32 binary_point;

    index = index;
    // __GET_GICV3_REG(ICC_BPR1, binary_point);
    binary_point = getBPR1();
    return binary_point;
}

u32 ArmGicGetIrqStatus(u32 index, int irq)
{
    u32 pending;
    u32 active;

    FT_ASSERTZERONUM(index < GIC_MAX_NR);

    irq = (irq - _gic_table[index].offset);
    FT_ASSERTZERONUM(irq >= 0);

    active = (GIC_DIST_ACTIVE_SET(_gic_table[index].dist_hw_base, irq) >> (irq % 32U)) & 0x1UL;
    pending = (GIC_DIST_PENDING_SET(_gic_table[index].dist_hw_base, irq) >> (irq % 32U)) & 0x1UL;

    return ((active << 1U) | pending);
}

void ArmGicSendAffinitySgi(u32 index, int irq, u32 cpu_mask, u32 routing_mode)
{
    (void)index;
    if (routing_mode)
    {
        /*  Write the ICC_SGI1R registers */
        __asm__ volatile("dsb 0xF" ::
                             : "memory");

        sendGroup1SGI((irq & 0x0FULL) << 24, 1ULL << 40, 0);
        __asm__ volatile("isb 0xF" ::
                             : "memory");
    }
    else
    {
        u32 cluster_id, target_list;
        while (ArmGicCpuMaskToAffval(&cpu_mask, &cluster_id, &target_list))
        {
            __asm__ volatile("dsb 0xF" ::
                                 : "memory");
            sendGroup1SGI(((irq & 0x0FULL) << 24), ((((cluster_id >> 8) & 0xFFULL) << GIC_RSGI_AFF1_OFFSET) | (((cluster_id >> 16) & 0xFFULL) << GIC_RSGI_AFF2_OFFSET) | (((cluster_id >> 24) & 0xFFull) << GIC_RSGI_AFF3_OFFSET)), 
                        target_list);
            __asm__ volatile("isb 0xF" ::
                                 : "memory");
        }
    }
}

u32 ArmGicGetHighPendingIrq(u32 index)
{
    u32 irq;
    FT_ASSERTZERONUM(index < GIC_MAX_NR);

    index = index;
    irq = getHPPIR1();
    // __GET_GICV3_REG(ICC_HPPIR1, irq);
    return irq;
}

u32 ArmGicGetInterfaceId(u32 index)
{
    FT_ASSERTZERONUM(index < GIC_MAX_NR);

    return GIC_CPU_IIDR(_gic_table[index].cpu_hw_base);
}

void ArmGicSetGroup(u32 index, int irq, u32 group)
{
    u32 igroupr;
    u32 shift;

    FT_ASSERTVOID(index < GIC_MAX_NR);
    FT_ASSERTVOID(group <= 1U);

    irq = (irq - _gic_table[index].offset);
    FT_ASSERTVOID(irq >= 0);

    igroupr = GIC_DIST_IGROUP(_gic_table[index].dist_hw_base, irq);
    shift = (irq % 32U);
    igroupr &= (~(1U << shift));
    igroupr |= ((group & 0x1U) << shift);

    GIC_DIST_IGROUP(_gic_table[index].dist_hw_base, irq) = igroupr;
}

u32 ArmGicGetGroup(u32 index, int irq)
{
    FT_ASSERTZERONUM(index < GIC_MAX_NR);

    irq = (irq - _gic_table[index].offset);
    FT_ASSERTZERONUM(irq >= 0);

    return (GIC_DIST_IGROUP(_gic_table[index].dist_hw_base, irq) >> (irq % 32U)) & 0x1UL;
}

static int ArmGicWaitRwp(u32 index, u32 irq)
{
    u32 rwp_bit;
    u32 base;

    FT_ASSERTZERONUM(index < GIC_MAX_NR);

    if (irq < 32)
    {
        u32 cpu_id = GetCpuId();

        FT_ASSERTZERONUM((cpu_id) < FT_CPUS_NR);
        base = _gic_table[index].redist_hw_base[cpu_id];
        rwp_bit = GICR_CTLR_RWP;
    }
    else
    {
        base = _gic_table[index].dist_hw_base;
        rwp_bit = GICD_CTLR_RWP;
    }

    while (__REG32(base) & rwp_bit)
    {
        ;
    }

    return 0;
}

int ArmGicDistInit(u32 index, u32 dist_base, int irq_start)
{
    u64 cpu0_affval;
    u32 gic_type, i;

    FT_ASSERTZERONUM(index < GIC_MAX_NR);
    _gic_table[index].dist_hw_base = dist_base;
    _gic_table[index].offset = irq_start;

    /* Find out how many interrupts are supported. */
    gic_type = GIC_DIST_TYPE(dist_base);
    _gic_max_irq = ((gic_type & 0x1fU) + 1U) * 32U;

    /*
     * The GIC only supports up to 1020 interrupt sources.
     * Limit this to either the architected maximum, or the
     * platform maximum.
     */
    if (_gic_max_irq > 1020U)
        _gic_max_irq = 1020U;
    if (_gic_max_irq > GIC_NR_IRQS) /* the platform maximum interrupts */
        _gic_max_irq = GIC_NR_IRQS;

    GIC_DIST_CTRL(dist_base) = 0x0U;
    /* Wait for register write pending */
    ArmGicWaitRwp(0, 32);

    /* Set all global interrupts to be level triggered, active low. */
    for (i = 32U; i < _gic_max_irq; i += 16U)
        GIC_DIST_CONFIG(dist_base, i) = 0x0U;

    ArmGicWaitRwp(0, 32);

    cpu0_affval = GetMainCpuAffval();
    /* Set all global interrupts to this CPU only. */
    for (i = 32U; i < _gic_max_irq; i++)
    {
        GIC_DIST_IROUTER_LOW(dist_base, i) = cpu0_affval;
        GIC_DIST_IROUTER_HIGH(dist_base, i) = cpu0_affval >> 32;
    }

    ArmGicWaitRwp(0, 32);

    /* Set priority on spi interrupts. */
    for (i = 32U; i < _gic_max_irq; i += 4U)
        GIC_DIST_PRI(dist_base, i) = 0xa0a0a0a0U;

    ArmGicWaitRwp(0, 32);
    /* Disable all interrupts. */
    for (i = 0U; i < _gic_max_irq; i += 32U)
    {
        GIC_DIST_PENDING_CLEAR(dist_base, i) = 0xffffffffU;
        GIC_DIST_ENABLE_CLEAR(dist_base, i) = 0xffffffffU;
    }

    ArmGicWaitRwp(0, 32);
    /* All interrupts defaults to IGROUP1(IRQ). */
    for (i = 0U; i < _gic_max_irq; i += 32U)
        GIC_DIST_IGROUP(dist_base, i) = 0xffffffffU;

    ArmGicWaitRwp(0, 32);

    /*
        The Distributor control register (GICD_CTLR) must be configured to enable the interrupt groups and to set the routing mode.
        Enable Affinity routing (ARE bits) The ARE bits in GICD_CTLR control whether affinity routing is enabled.
        If affinity routing is not enabled, GICv3 can be configured for legacy operation.
        Whether affinity routing is enabled or not can be controlled separately for Secure and Non-secure state.
        Enables GICD_CTLR contains separate enable bits for Group 0, Secure Group 1 and Non-secure Group 1:
        GICD_CTLR.EnableGrp1S enables distribution of Secure Group 1 interrupts.
        GICD_CTLR.EnableGrp1NS enables distribution of Non-secure Group 1 interrupts.
        GICD_CTLR.EnableGrp0 enables distribution of Group 0 interrupts.
    */
    GIC_DIST_CTRL(dist_base) = GICD_CTLR_ARE_S | GICD_CTLR_ARE_NS | GICD_CTLR_ENGRP1NS;

    enableGroup1Ints();
    return 0;
}

int ArmGicRedistAddressSet(u32 index, u32 redist_addr, u32 cpu_id)
{
    FT_ASSERTZERONUM(index < GIC_MAX_NR);
    FT_ASSERTZERONUM((cpu_id) < FT_CPUS_NR);
    _gic_table[index].redist_hw_base[cpu_id] = redist_addr;

    return 0;
}

int ArmGicCpuInterfaceAddressSet(u32 index, u32 interface_addr, u32 cpu_id)
{
    FT_ASSERTZERONUM(index < GIC_MAX_NR);
    FT_ASSERTZERONUM((cpu_id) < FT_CPUS_NR);
    _gic_table[index].cpu_hw_base[cpu_id] = interface_addr;

    return 0;
}

int ArmGicRedistInit(u32 index)
{
    u32 i;
    u32 base;
    u32 reg_value;
    u32 cpu_id = GetCpuId();

    FT_ASSERTZERONUM(index < GIC_MAX_NR);
    FT_ASSERTZERONUM((cpu_id) < FT_CPUS_NR);

    base = _gic_table[index].redist_hw_base[cpu_id];
    // printf("redist base %x \r\n", base);
    /* redistributor enable */
    // reg_value = GIC_RDIST_WAKER(base);
    // reg_value &= ~(1U << 1);
    // GIC_RDIST_WAKER(base) = reg_value;

    // do
    // {
    //     reg_value = GIC_RDIST_WAKER(base);
    // } while ((reg_value & 0x4) != 0);

    GIC_RDIST_WAKER(base) &= ~(1U << 1);
    while (GIC_RDIST_WAKER(base) & (1 << 2))
    {
        ;
    }

    /* Disable all sgi and ppi interrupt */
    GIC_RDISTSGI_ICENABLER0(base) = 0xFFFFFFFF;
    ArmGicWaitRwp(0, 0);

    /* Clear all inetrrupt pending */
    GIC_RDISTSGI_ICPENDR0(base) = 0xFFFFFFFF;

    /* the corresponding interrupt is Group 1 or Non-secure Group 1. */
    GIC_RDISTSGI_IGROUPR0(base, 0) = 0xFFFFFFFF;
    GIC_RDISTSGI_IGRPMODR0(base, 0) = 0xFFFFFFFF;

    /* Configure default priorities for SGI 0:15 and PPI 16:31. */
    for (i = 0; i < 32; i += 4)
    {
        GIC_RDISTSGI_IPRIORITYR(base, i) = 0xa0a0a0a0U;
    }

    /* Trigger level for PPI interrupts*/
    GIC_RDISTSGI_ICFGR1(base) = 0x0U; // PPI is level-sensitive.
    return 0;
}

int ArmGicCpuInit(u32 index)
{
    u32 value;
    FT_ASSERTZERONUM(index < GIC_MAX_NR);
    value = ArmGicGetSystemRegisterEnableMask(index);
    value |= (1U << 0);
    ArmGicSetSystemRegisterEnableMask(index, value);
    setICC_CTLR_EL1(0);
    // __SET_GICV3_REG(ICC_CTLR, 0);
    ArmGicSetInterfacePriorMask(index, 0xFFU);
    /* Enable group1 interrupt */
    enableGroup1Ints();
    // __SET_GICV3_REG(ICC_IGRPEN1, value);
    ArmGicSetBinaryPoint(0, 0);

    /* ICC_BPR0_EL1 determines the preemption group for both
       Group 0 and Group 1 interrupts.
       */
    value = 0x1U;
    setICC_CTLR_EL1(value);

    // __SET_GICV3_REG(ICC_CTLR, value);

    return 0;
}


void ArmGicDumpType(u32 index)
{
    u32 gic_type;

    gic_type = GIC_DIST_TYPE(_gic_table[index].dist_hw_base);
    printf("GICv%ld on %x, max IRQs: %d, %s security extension(%08x)\r\n",
           (GIC_DIST_ICPIDR2(_gic_table[index].dist_hw_base) >> 4U) & 0xfUL,
           _gic_table[index].dist_hw_base,
           _gic_max_irq,
           gic_type & (1U << 10U) ? "has" : "no",
           gic_type);
}

void ArmGicDump(u32 index)
{
    u32 i, k;

    k = ArmGicGetHighPendingIrq(0);
    printf("--- high pending priority: %d(%08x)\r\n", k, k);
    printf("--- hw mask ---\r\n");
    for (i = 0U; i < _gic_max_irq / 32U; i++)
    {
        printf("0x%08x, ",
               GIC_DIST_ENABLE_SET(_gic_table[index].dist_hw_base,
                                   i * 32U));
    }
    printf("\r\n--- hw pending ---\r\n");
    for (i = 0U; i < _gic_max_irq / 32U; i++)
    {
        printf("0x%08x, ",
               GIC_DIST_PENDING_SET(_gic_table[index].dist_hw_base,
                                    i * 32U));
    }
    printf("\r\n--- hw active ---\r\n");
    for (i = 0U; i < _gic_max_irq / 32U; i++)
    {
        printf("0x%08x, ",
               GIC_DIST_ACTIVE_SET(_gic_table[index].dist_hw_base,
                                   i * 32U));
    }
    printf("\r\n");
}

long gic_dump(void)
{
    ArmGicDumpType(0);
    ArmGicDump(0);

    return 0;
}
